# -*- coding: utf-8 -*-

from flask import Flask,render_template
from flask_migrate import Migrate
from .configs import config
from .exts import db,setup_log,bootstrap
from .errors import configure_errorhandlers
from .models import User
from flask_wtf import FlaskForm
from flask_mail import Mail
from flask_wtf.csrf import CSRFProtect
from flask_session import Session
from flask_login import LoginManager

import logging
from logging.handlers import RotatingFileHandler


def create_app(config_name=None):
    if config_name is None:
        config_name = 'default'

    app = Flask(__name__)
    app.config.from_object(config[config_name])

    # db
    db.init_app(app) # 初始化数据库和app的绑定
    bootstrap.init_app(app) # 初始化bootstrap和app的绑定
    
    # migrate = Migrate(app,db)
    
    login_manager = LoginManager()
    login_manager.init_app(app) # 登录管理器
    login_manager.login_view = 'auth.login' # 登录视图
    
    # mail
    mail = Mail(app)
    mail.init_app(app)
    
    # CSRFProtect(app) # 开启CSRF防范功能
    
    Session(app) # 开启session功能
    
    # TODO 启用日志
    # setup_log(config[config_name])    
    # app.__init__.py 初始化rootlogger
    # rootLogger = logging.getLogger(__name__)
    # rootLogger.setLevel(logging.DEBUG)
    # socketHandler = logging.handlers.SocketHandler('localhost',logging.handlers.DEFAULT_TCP_LOGGING_PORT)
    # rootLogger.addHandler(socketHandler)
    # rootLogger.setLevel(logging.DEBUG)
    
    
    @login_manager.user_loader
    def load_user(user_id):
        
        user = User.query.get(int(user_id))
        return user
        
    # from . import  errors
    
    # 注册蓝图    
    register_blueprint(app) 
    
    #注册日志处理器
    register_log(app)
    
    register_hooks(app)# 注册全局钩子函数
    
    configure_errorhandlers(app) # 配置全局错误钩子函数
    
    return app

# 通过这个方法插入到app中
def register_blueprint(app): # 注册蓝图
    # from app.controllers.todo import todo_bp # 方法1
    # from .todo import todo_bp  # 方法1： .todo 当前目录下的文件名    
    
    from app.blueprints.todo import todo_bp # 方法2： 直接导入蓝图模块
    from app.blueprints.watchlist  import watchlist_bp
    from app.blueprints.auth import auth_bp
    
    # 最好还是在注册的同时定义前缀。这使得前缀的定义可以集中到顶级目录中
    app.register_blueprint(todo_bp,url_prefix='/todo') # 注册蓝图
    app.register_blueprint(watchlist_bp,url_prefix='/watchlist')
    app.register_blueprint(auth_bp,url_prefix='/')


def register_hooks(app):# 注册钩子函数   
    from .hooks import before_request, after_request, teardown_request 
    app.before_request(before_request)
    app.after_request(after_request)
    app.teardown_request(teardown_request)
    

def register_log(app):
    # 创建日志记录器
    logger = logging.getLogger('werkzeug')
    # logger.disabled = True # 不输出flask的请求地址到控制台中
    
    logger = logging.getLogger(__name__)
    
    logger.setLevel(logging.DEBUG)
   
    # 创建控制台处理器
    console_handler = logging.StreamHandler() 
    console_handler.setLevel(logging.INFO)  # 控制台只显示INFO及以上级别的日志
    
    # 创建文件处理器
    log_filename = app.config['LOG_FILE']
    # file_handler = logging.FileHandler(filename=log_filename)
    file_handler = RotatingFileHandler(filename=log_filename, 
                                           maxBytes=10 * 1024 * 1024, backupCount=10)
    file_handler.setLevel(logging.DEBUG) # 文件中记录所哟DEBUG及以上级别的日志
    
    # 定义日志输出格式
    fmt = '%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s'
    fmt = "%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s"
    fmt = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    fmt = '%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s:%(message)s'
    formatter = logging.Formatter(fmt)
    console_handler.setFormatter(formatter)
    file_handler.setFormatter(formatter)

    # 将处理器添加到日志记录器
    logger.addHandler(console_handler)
    logger.addHandler(file_handler)
    
    # 将Flask应用的日志记录器与自定义日期记录器关联
    app.logger.handlers = logger.handlers
    app.logger.setLevel(logger.level)
    
    # 记录一条启动信息
    app.logger.info('Flask app is starting...')

 



